package com.nkym.wypan.service.impl;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.google.gson.Gson;
import com.nkym.wypan.enums.ResponseStatus;
import com.nkym.wypan.enums.socket.WSRespTypeEnum;
import com.nkym.wypan.model.entity.chat.AuthRoomMessage;
import com.nkym.wypan.model.entity.chat.Message;
import com.nkym.wypan.model.entity.chat.TextChatMessage;
import com.nkym.wypan.model.resp.socket.TextMessageResp;
import com.nkym.wypan.model.resp.socket.UserInfoMessageResp;
import com.nkym.wypan.model.resp.socket.WsMessageResp;
import com.nkym.wypan.service.RoomMemberService;
import com.nkym.wypan.service.UserService;
import com.nkym.wypan.service.WebSocketService;
import com.nkym.wypan.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

import static com.nkym.wypan.enums.ResponseStatus.*;
import static com.nkym.wypan.enums.socket.WSRespTypeEnum.*;

/**
 * @ClassName WebSocketServiceImpl
 * @Author nkym
 * @Date 2023-11-10 13:11
 * @Version 1.0
 */
@Service
@Slf4j
public class WebSocketServiceImpl implements WebSocketService {
    @Resource
    UserService userService;
    @Resource
    RoomMemberService roomMemberService;
    private static final CopyOnWriteArraySet<WebSocketSession> webSocketSet = new CopyOnWriteArraySet<WebSocketSession>();
    /**
     * 房间 对应的 所有会话
     */
    private static final ConcurrentHashMap<Long, Set<WebSocketSession>> roomSession = new ConcurrentHashMap<>();
    private static final ConcurrentHashMap<WebSocketSession, Long> sessionUser = new ConcurrentHashMap<>();


    @Override
    public void addSession(WebSocketSession session) {
        webSocketSet.add(session);
    }

    @Override
    public void removeSession(WebSocketSession session) {
        System.out.println(sessionUser.get(session) + "已经离线");
        webSocketSet.remove(session);
        sessionUser.remove(session);
    }

    /**
     * 用户连接 房间
     *
     * @param session
     * @param msg
     */
    @Override
    public void userJoinRoom(WebSocketSession session, Message msg) {
        AuthRoomMessage authMsg = JSONUtil.toBean((JSONObject) msg.getData(), AuthRoomMessage.class);
        String token = authMsg.getToken();
        Long uid = JwtUtils.getUidOrNull(token);

        Long roomId = authMsg.getRoomId();
        boolean isRoomMember = roomMemberService.checkUserIsRoomMember(roomId, uid);
        if (!isRoomMember) {
            sendError(session, NOT_ROOM_MEMBER);
        }
        //会话和 用户的映射
        sessionUser.put(session, uid);
        Set<WebSocketSession> set = roomSession.getOrDefault(roomId, new HashSet<>());
        set.add(session);
        //房间  和 所有会话的映射
        roomSession.put(roomId, set);
        //发送给 客户端 保存用户信息
        sendUserInfoMsg(session, uid);
    }

    /**
     * 转发 聊天内容
     *
     * @param session
     * @param msg
     */
    @Override
    public void sendChatMsg(WebSocketSession session, Message msg) {
        TextChatMessage chatMsg = JSONUtil.toBean((JSONObject) msg.getData(), TextChatMessage.class);
        String content = chatMsg.getContent();
        Long roomId = chatMsg.getRoomId();
        sendToAllUserInRoom(content, roomId);

    }
    private void sendToAllUserInRoom(String content, Long roomId) {

        TextMessageResp resp = new TextMessageResp();
        resp.setContent(content);
        resp.setType(MESSAGE.getType());
        sendMsgGroup(roomId, resp);
    }

    private void sendUserInfoMsg(WebSocketSession session, Long uid) {
        UserInfoMessageResp resp = new UserInfoMessageResp();
        resp.setUid(String.valueOf(uid));
        resp.setType(USERINFO_MESSAGE.getType());
        //发送消息

        sendMsg(session, resp);
    }

    private void sendError(WebSocketSession session, ResponseStatus responseStatus) {
        //组装消息体
        TextMessageResp textMessageResp = new TextMessageResp();
        textMessageResp.setContent(responseStatus.getDesc());
        textMessageResp.setType(ERROR_MESSAGE.getType());
        sendMsg(session, textMessageResp);
    }

    private void sendMsg(WebSocketSession session, WsMessageResp messageResp) {
        String json = new Gson().toJson(messageResp);
        try {
            session.sendMessage(new TextMessage(json));
        } catch (Exception e) {
            log.info("发送失败");
            e.printStackTrace();
        }
    }

    private void sendMsgGroup(Long roomId, WsMessageResp messageResp) {
        //todo 保存群聊记录到所有用户中
        //todo 推送当前房间所有在线人员(异步推送)
        Set<WebSocketSession> webSocketSessions = roomSession.get(roomId);
        if (webSocketSessions == null) {
            return;
        }
        for (WebSocketSession session : webSocketSessions) {
            if (!webSocketSet.contains(session)) {
                continue;
            }
            String respJson = new Gson().toJson(messageResp);
            TextMessage message = new TextMessage(respJson);
            try {
                session.sendMessage(message);
            }catch (Exception e){
                log.error("发消息错误");
                e.printStackTrace();
            }
        }
    }

    ;
}
